package com.googlecode.imanager.client.bridge;

import java.io.OutputStream;
import java.util.Iterator;

import com.googlecode.imanager.InterfaceManager;
import com.googlecode.imanager.client.Application;
import com.googlecode.imanager.client.Container;
import com.googlecode.imanager.client.Control;
import com.googlecode.imanager.client.Document;
import com.googlecode.imanager.client.Focusable;
import com.googlecode.imanager.client.action.Action;
import com.googlecode.imanager.client.bridge.style.ITheme;
import com.googlecode.imanager.client.exception.BridgeException;
import com.googlecode.imanager.client.exception.IMException;
import com.googlecode.imanager.client.io.Path;
import com.googlecode.imanager.client.media.Image;
import com.googlecode.imanager.client.util.Logger;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public abstract class BridgeManager {
    
    public static final String IMANAGER_PACKAGE = InterfaceManager.class.getPackage().getName();
    
    private static Class<? extends BridgeManager> implClass;
    
    private static BridgeManager instance;
    
    public static BridgeManager getInstance(){
        if (instance == null){
            synchronized (BridgeManager.class) {
                // check instance again to prevent create it twice
                if (instance == null){
                    String managerClassName;
                    
                    if (implClass != null){
                        try {
                            instance = implClass.newInstance();
                            return instance;
                        } catch (Exception e) {
                            // ignore
                        }
                    }
                    
                    try {
                        managerClassName = System.getProperty(BridgeManager.class.getName());
                    } catch (SecurityException e) {
                        managerClassName = null;
                    }
                    
                    if (managerClassName != null) {
                        if (managerClassName.length() != 0) {
                            try {
                                instance = (BridgeManager) Class.forName(managerClassName).newInstance();
                            } catch (Exception e) {
                                managerClassName = null;
                            }
                        } else {
                            managerClassName = null;
                        }
                    }
                    
                    if (managerClassName == null){
                        managerClassName = IMANAGER_PACKAGE + ".core.base.DefaultManager";
                        
                        try {
                            instance = (BridgeManager) Class.forName(managerClassName).newInstance();
                        } catch (Exception e) {
                            throw new BridgeException(e);
                        }
                    }
                }
            }
        }
        return instance;
    }
    
    protected static synchronized void setManagerImplementation(
            Class<? extends BridgeManager> managerClass){
        instance = null;
        implClass = managerClass;
    }
    
    public abstract void generateBridge(Document document, BridgeType bridgeType, OutputStream output) throws IMException;
    
    public abstract void generateBridge(Application application, BridgeType bridgeType, OutputStream output) throws IMException;
    
    public abstract void changeParent(Control control, Container parent);
    
    public abstract void changeApplication(Document document, Application parent);
    
    public abstract IComponent lookupImplementation(Object source);
        
    public abstract Image loadImage(Document owner, Path path);

    public abstract boolean executeAction(Action action, Control sender);

    public abstract Logger getLogger(Class<?> ownerClass);

    public abstract void setFocusControl(Application application, Focusable focusControl);

    public abstract ITheme getDefaultTheme(BridgeType type);

    public abstract Iterator<String> getControlHierarchy(String controlClassName);
    
    public abstract String getControlSuperClass(String controlClassName);
    
}
